package cgl.narada.test.security;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.TimeZone;

import org.apache.log4j.PropertyConfigurator;

import cgl.narada.discovery.topics.Entity;
import cgl.narada.discovery.topics.TopicDiscoveryClient;
import cgl.narada.discovery.topics.Topics;
import cgl.narada.discovery.topics.messages.SignedTopicAdvertisement;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.service.security.kmc.KMCClient;
import cgl.narada.service.security.kmc.SignedSecurityToken;
import cgl.narada.service.security.kmc.TopicRights;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;

/**
 * DEMO Program<br>
 * Tries to publish / subscribe to a secure topic with correct credentials. <br>
 * Tries to publish / subscribe to a secure topic without credentials <br>
 * Tries to publish / subscribe to a secure topic with PHONY credentials <br>
 * Created on Sep 9, 2005
 * 
 * @author Harshawardhan Gadgil (hgadgil@grids.ucs.indiana.edu)
 */
public class SecureTopicClient {

    static {
        PropertyConfigurator
                .configure("/home/hgadgil/research/hpsearch/conf/log4j.properties");
        // PropertyConfigurator
        // .configure("c:\\Home\\projects\\CGL-HPSEARCH\\conf\\log4j.properties");

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        SecureTopicClient stc = new SecureTopicClient();
        stc
                .testCorrectCredentials("/home/hgadgil/tmp/narada/keystore/NBSecurityTest.keys");

        stc
                .testRequestSecurityToken("/home/hgadgil/tmp/narada/keystore/NBSecurityTest.keys");

        // stc
        // .testCorrectCredentials("c:\\Home\\tmpFiles\\KEYSTORES\\NBSecurityTest.keys");
        // stc
        // .testRequestSecurityToken("c:\\Home\\tmpFiles\\KEYSTORES\\NBSecurityTest.keys");

    }

    public void testCorrectCredentials(String keystore) {
        CertificateManager certMan = new CertificateManager();
        certMan.init(keystore, null);

        PublicKey rootCA = CertificateUtil.getPublicKey(certMan,
                certMan.ROOT_CA_ALIAS);

        Certificate c1_cert = CertificateUtil.getCertificate(certMan, "c1");
        PrivateKey c1_priv = CertificateUtil.getPrivateKey(certMan, "c1");

        Calendar until = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
        until.add(Calendar.HOUR, 1);

        Entity e = new Entity(
                9999,
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt",
                "c1", c1_cert, c1_priv, rootCA, "localhost", "25000", "niotcp");

        // Entity e = new Entity(9999,
        // "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt",
        // "c1", c1_cert, c1_priv, rootCA, "localhost", "25000", "niotcp");

        if (e == null) {
            System.out.println("ERRRORRRR !!!!");
            return;
        }

        createTopic(e, "/secureTopic/NotSECURE_REALLY",
                TemplateProfileAndSynopsisTypes.STRING, until);

        createTopic(e, "/secureTopic", TemplateProfileAndSynopsisTypes.STRING,
                until);

        KMCClient client = new KMCClient(c1_cert, c1_priv, rootCA, "/kmc/c1",
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt");

        // KMCClient client = new KMCClient(c1_cert, c1_priv, rootCA, "/kmc/c1",
        // "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt");

        // Get Signed Topic Ad
        SignedTopicAdvertisement sta = e
                .getSignedTopicAdvertisement("/secureTopic");

        // Set the access control lists
        Hashtable pubs = new Hashtable();
        pubs.put(((X509Certificate) c1_cert).getSubjectDN().getName(), until);
        pubs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until);

        Hashtable subs = new Hashtable();
        subs.put(((X509Certificate) c1_cert).getSubjectDN().getName(), until);
        subs.put("CN=client1,OU=CGL,O=IU,L=Bloomington,C=US", until);

        // Ok, now register the topic and get a security token
        SecureTopicKeyResponse resp = client.registerTopic(pubs, subs, sta,
                c1_cert, until, null, 256, 5000);

        // Check the response
        SignedSecurityToken tok = resp.getSignedSecurityToken();
        System.out.println("VERIFICATION: " + tok.verify());
        System.out.println("Publish: "
                + tok.getSecurityToken().getRights().hasPublishRight());
        System.out.println("Subscribe: "
                + tok.getSecurityToken().getRights().hasSubscribeRight());
    }

    public void testRequestSecurityToken(String keystore) {
        // Phase 2:
        System.out.println("\n-----------------------------------------\n"
                + "NOW TRYING TO REQUEST SECURITY KEY...\n"
                + "---------------------------------------------");

        CertificateManager certMan = new CertificateManager();
        certMan.init(keystore, null);

        PublicKey rootCA = CertificateUtil.getPublicKey(certMan,
                certMan.ROOT_CA_ALIAS);

        Certificate c2_cert = CertificateUtil.getCertificate(certMan, "c2");
        PrivateKey c2_priv = CertificateUtil.getPrivateKey(certMan, "c2");

        // First discover the topic...
        SignedTopicAdvertisement[] stas = discoverTopics(c2_cert, c2_priv,
                "^/secureTopic*", Topics.MATCHING_REGEX, 2);

        KMCClient client2 = new KMCClient(c2_cert, c2_priv, rootCA, "/kmc/c2",
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt");

        // KMCClient client2 = new KMCClient(c2_cert, c2_priv, rootCA,
        // "/kmc/c2",
        // "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt");

        TopicRights reqRights = new TopicRights(TopicRights.PUBLISH_RIGHT);

        // Now try to get the security token...
        for (int k = 0; k < stas.length; k++) {

            SecureTopicKeyResponse r2 = client2.requestTopicKey(stas[k]
                    .getTopicAd().getTopicSynopsis(), c2_cert, reqRights, 5000);

            if (r2 == null)
                System.out.println("Request Denied / Timeout occurred !");
            else {
                System.out.println("Sec Token:"
                        + r2.getSignedSecurityToken().getSecurityToken()
                                .getValidity().toString());
            }
        }
    }

    public boolean createTopic(Entity e, String topicName, int topicType,
            Calendar until) {

        if (e.sendTDNDiscoveryRequest(10000)) {
            System.out.println("Found TDN ! Proceeding to create TOPIC !!");

            if (!e.createTopic("SELF", until, "Test Topic", topicType,
                    topicName, null, 5000)) {
                System.err.println("Could not create topic ! Aborting...");
                return false;
            }

            System.out.println("TOPIC Created: UUID -> "
                    + e.getTopicUUID(topicName));
            return true;
        } else {
            System.out
                    .println("NO TDN found within specified timeout period !!");
            return false;
        }
    }

    public SignedTopicAdvertisement[] discoverTopics(Certificate cert,
            PrivateKey priv, String synopsis, int matchType, int maxTopics) {

        TopicDiscoveryClient disco = new TopicDiscoveryClient(
                15000,
                "/home/hgadgil/projects/NB1rc1/config/ServiceConfiguration.txt",
                cert, priv, "localhost", "25000", "niotcp");

        // TopicDiscoveryClient disco = new TopicDiscoveryClient(15000,
        // "c:\\Home\\projects\\NB1rc1\\config\\ServiceConfiguration.txt",
        // cert, priv, "localhost", "25000", "niotcp");

        SignedTopicAdvertisement[] stas = disco.discover(matchType, synopsis,
                null, maxTopics);

        disco.close();

        return stas;
    }
}
